/*
 *
 */
package org.jiscinvolve.astrodabis.barberry.hibernate.data;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.Serializable;
import java.util.Collections;

import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.JoinColumn;
import javax.persistence.GenerationType;
import javax.persistence.GeneratedValue;
import javax.persistence.UniqueConstraint;

import org.hibernate.annotations.Index;
import org.hibernate.annotations.NamedQuery;
import org.hibernate.annotations.NamedQueries;
import org.hibernate.annotations.GenericGenerator;

import org.springframework.stereotype.Repository;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.Primary;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; 

import org.jiscinvolve.astrodabis.barberry.common.core.Womble;
import org.jiscinvolve.astrodabis.barberry.common.core.Account;
import org.jiscinvolve.astrodabis.barberry.common.core.Identifier;
import org.jiscinvolve.astrodabis.barberry.common.core.SimpleIdent;
import org.jiscinvolve.astrodabis.barberry.common.core.AbstractIdent;

import org.jiscinvolve.astrodabis.barberry.common.data.TapRow;
import org.jiscinvolve.astrodabis.barberry.common.data.TapTable;
import org.jiscinvolve.astrodabis.barberry.common.data.TapColumn;
import org.jiscinvolve.astrodabis.barberry.common.data.TapService;

import org.jiscinvolve.astrodabis.barberry.hibernate.core.OwnedEntity;
import org.jiscinvolve.astrodabis.barberry.hibernate.core.TrackedEntity;
import org.jiscinvolve.astrodabis.barberry.hibernate.core.AbstractFactory;

import org.jiscinvolve.astrodabis.barberry.common.core.exception.*;
import org.jiscinvolve.astrodabis.barberry.hibernate.annotation.*;

/**
 *
 */
@Entity
@Table(
    name = TapColumnEntity.DB_TABLE_NAME,
    uniqueConstraints = @UniqueConstraint(
        columnNames = {
            TapColumnEntity.DB_PARENT_COL,
            TapColumnEntity.DB_NAME_COL
            }
        )
    )
@NamedQueries(
        {
        @NamedQuery(
            name  = "tapcolumn-all",
            query = "FROM TapColumnEntity ORDER BY name, ident"
            ),
        @NamedQuery(
            name  = "tapcolumn-name",
            query = "FROM TapColumnEntity where name = :name ORDER BY ident"
            ),
        @NamedQuery(
            name  = "tapcolumn-parent",
            query = "FROM TapColumnEntity where parent = :parent ORDER BY name, ident"
            ),
        @NamedQuery(
            name  = "tapcolumn-parent-name",
            query = "FROM TapColumnEntity where parent = :parent AND name = :name ORDER BY ident"
            ),
        @NamedQuery(
            name  = "tapcolumn-parent-ident",
            query = "FROM TapColumnEntity where parent = :parent AND ident = :ident"
            )
        }
    )
public class TapColumnEntity
extends TrackedEntity
implements TapColumn
    {

    /**
     * Our debug logger.
     * 
     */
    private static Log log = LogFactory.getLog(TapColumnEntity.class);

    public static final String DB_TABLE_NAME = "tapcolumns";
    public static final String DB_PARENT_COL = "parent";
    public static final String DB_IDENT_COL  = "ident";
    public static final String DB_NAME_COL   = "name";
    public static final String DB_TEXT_COL   = "text";

    @Repository
    public static class Factory
    extends AbstractFactory<TapColumn, TapColumnEntity>
    implements TapColumn.Factory
        {

        @Override
        public Identifier ident(String ident)
            {
            if ((ident == null) || ("-".equals(ident)))
                {
                return null ;
                }
            else {
                try {
                    return new SimpleIdent<Long>(
                        Long.valueOf(
                            ident
                            )
                        );
                    }
                catch (NumberFormatException ouch)
                    {
                    throw new IdentFormatException(
                        ouch
                        );
                    }
                }
            }

        @Override
        @CreateObject
        public TapColumn create(TapTable parent, String name)
            {
            return createQuick(
                parent,
                name
                );
            }

        @Override
        @CreateQuick
        public TapColumn createQuick(TapTable parent, String name)
            {
            TapColumn found = select(
                parent,
                name
                );
            if (found != null)
                {
                return found ;
                }
            else {
                return hibernate().insert(
                    new TapColumnEntity(
                        parent,
                        name
                        )
                    );
                }
            }

        @Override
        @SelectObject
        public TapColumn select(Identifier ident)
            {
            return hibernate().select(
                TapColumnEntity.class,
                ident
                );
            }

        @Override
        @SelectObject
        public Iterable<TapColumn> select()
            {
            return hibernate().iterable(
                hibernate().query(
                    "tapcolumn-all"
                    )
                );
            }

        @Override
        @SelectObject
        public Iterable<TapColumn> select(String name)
            {
            if (name == null)
                {
                return Collections.emptyList();
                }
            else {
                return hibernate().iterable(
                    hibernate().query(
                        "tapcolumn-name"
                        ).setString(
                            "name",
                            name
                            )
                    );
                }
            }

        @Override
        @SelectObject
        public Iterable<TapColumn> select(TapTable parent)
            {
            if (parent == null)
                {
                return Collections.emptyList();
                }
            else {
                return hibernate().iterable(
                    hibernate().query(
                        "tapcolumn-parent"
                        ).setEntity(
                            "parent",
                            parent
                            )
                    );
                }
            }

        @Override
        @SelectObject
        public TapColumn select(TapTable parent, String name)
            {
            if ((parent == null) || (name == null))
                {
                return null ;
                }
            else {
                return hibernate().first(
                    hibernate().query(
                        "tapcolumn-parent-name"
                        ).setEntity(
                            "parent",
                            parent
                        ).setString(
                            "name",
                            name
                            )
                    );
                }
            }

        @Override
        @SelectObject
        public TapColumn select(TapTable parent, Identifier ident)
            {
            if ((parent == null) || (ident == null))
                {
                return null ;
                }
            else {
                return hibernate().first(
                    hibernate().query(
                        "tapcolumn-parent-ident"
                        ).setEntity(
                            "parent",
                            parent
                        ).setParameter(
                            "ident",
                            ident.value()
                            )
                    );
                }
            }
        }

    protected TapColumnEntity()
        {
        super();
        }

    protected TapColumnEntity(TapTable parent, String name)
        {
        this(
            parent,
            name,
            null
            );
        }

    protected TapColumnEntity(TapTable parent, String name, String text)
        {
        super(true);
        this.parent = parent ;
        this.name = name ;
        this.text = text ;
        }

    @Id
    @Column(
        name = DB_IDENT_COL,
        unique = true,
        nullable = false,
        updatable = false
        )
    @GeneratedValue(
        generator="tapmeta-hilo"
        )
    @GenericGenerator(
        name="tapmeta-hilo",
        strategy="hilo"
        )
    protected Long ident ;

    @Override
    public Identifier ident()
        {
        return new AbstractIdent()
            {
            @Override
            public Serializable value()
                {
                return ident ;
                }
            };
        }

    @ManyToOne(
        targetEntity = TapTableEntity.class
        )
    @JoinColumn(
        name = DB_PARENT_COL,
        unique = false,
        nullable = false,
        updatable = false
        )
    private TapTable parent;

    @Override
    public TapTable parent()
        {
        return this.parent ;
        }

    @Column(
        name = DB_NAME_COL,
        unique = false,
        nullable = false,
        updatable = false
        )
    private String name ;

    @Override
    public String name()
        {
        return this.name ;
        }

    @Column(
        name = DB_TEXT_COL,
        unique = false,
        nullable = true,
        updatable = true
        )
    private String text ;

    @Override
    public String text()
        {
        return this.text ;
        }

    @Override
    public boolean equals(Object that)
        {
        if (this == that)
            {
            return true ;
            }
        if (this.ident == null)
            {
            return false ;
            }
        if (that instanceof TapColumnEntity)
            {
            return this.ident.equals(
                ((TapColumnEntity)that).ident
                );
            }
        if (that instanceof TapColumn)
            {
            return this.ident().equals(
                ((TapColumn)that).ident()
                );
            }
        return false ;
        }

    @Override
    public TapRows rows()
        {
        return new TapRows()
            {

            @Override
            public TapRow create(String value)
                {
                return Womble.womble().rows().create(
                    TapColumnEntity.this,
                    value
                    );
                }

            @Override
            public TapRow createQuick(String value)
                {
                return Womble.womble().rows().createQuick(
                    TapColumnEntity.this,
                    value
                    );
                }

            @Override
            public TapRow select(String value)
                {
                return Womble.womble().rows().select(
                    TapColumnEntity.this,
                    value
                    );
                }

            @Override
            public Iterable<TapRow> select()
                {
                return Womble.womble().rows().select(
                    TapColumnEntity.this
                    );
                }
            };
        }

    @Override
    public String toString()
        {
        StringBuilder builder = new StringBuilder();
        builder.append(
            "Column["
            );
        builder.append(
            this.ident
            );
        builder.append(
            "]{ "
            );
        builder.append(
            this.parent().toString()
            );
        builder.append(
            ", name{"
            );
        builder.append(
            this.name()
            );
        builder.append(
            "}}"
            );
        return builder.toString();
        }
    }

